/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package msigraphx.handler;

import com.mxgraph.model.mxCell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
import java.io.IOException;
import java.util.List;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//import java.awt.event.MouseListener;
//import java.util.ArrayList;
//import java.util.Collection;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Vector;
//import msigraphx.graph.BayesianNetwork;
//import msigraphx.graph.NetworkVertex;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import org.jdesktop.application.SingleFrameApplication;
//import msigraphx.gibbsSampler.CondDistr;
import msigraphx.gibbsSampler.RandomVariableValue;
//import msigraphx.gibbsSampler.VarDistr;
import msigraphx.graph.BayesianNetwork;
import msigraphx.graph.NetworkVertex;

/**
 *
 * @author adam
 */
public class ViewNetworkHandler extends msigraphx.MSIGraphXView {

    private Map<mxGraph, BayesianNetwork> networks = new HashMap<mxGraph, BayesianNetwork>();
//    private ArrayList<mxGraph> graphs = new ArrayList<mxGraph>();

    public ViewNetworkHandler(SingleFrameApplication app) {
        super(app);
        setupComponents();
//        addNetwork(getBayes());
    }

    private void addEdges(BayesianNetwork network, mxGraph graph, Iterator i, Object parent) {
        i = network.getVertexes().entrySet().iterator();
        graph.getModel().beginUpdate();
        try {
            int indexOfParent = 0;
            while (i.hasNext()) {
                Map.Entry<String, NetworkVertex> entry = (Map.Entry) i.next();
                String parentLabel = entry.getKey();
                List<NetworkVertex> children = entry.getValue().getChildren();
                for (NetworkVertex child : children) {
                    String childLabel = child.getName();
                    graph.selectVertices();
                    Object[] vertices = graph.getSelectionCells();
                    mxCell edge = null;
                    for (Object obj : vertices) {
                        mxCell vertex = (mxCell) obj;
                        if (vertex.getValue().equals(parentLabel)) {
                            edge = addEdge(vertex);
                        }
                        if (vertex.getValue().equals(childLabel)) {
                            edge = addEdge(vertex);
                        }
                    }
                    edge.setValue("0");
                    //                    if (parentVertex != null && childVertex != null) {
                    //                        graph.insertEdge(parent, null, parentVertex, childVertex, parent);
                    //                    }
                }
            }
        } finally {
            graph.setSelectionCell(parent);
            graph.getModel().endUpdate();
        }
    }

    private void addVertices(mxGraph graph, Iterator i, Object parent, int x, int y, BayesianNetwork network) {
        graph.getModel().beginUpdate();
        try {
            while (i.hasNext()) {
                Map.Entry entry = (Map.Entry) i.next();
                graph.insertVertex(parent, null, entry.getKey(), x, y, 80, 30);
                x += 150;
                int w = (int) Math.sqrt(network.getVertexes().size()) * 100;
                if (x > w) {
                    x = 10;
                    y += 100;
                }
            }
        } finally {
            graph.getModel().endUpdate();
        }
    }

    private void openButtonMouseClicked(MouseEvent evt) {
        JFileChooser openFile = new JFileChooser("/media/Dane/Studia/MSI/Projekt/MSIGraphX/");
        int returnVal = openFile.showDialog(jPanel1, null);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = openFile.getSelectedFile();
            NetworkReader read = new NetworkReader();
            try {
                addNetwork(read.readFile(file.getPath()));
            } catch (IOException ex) {
                Logger.getLogger(ViewNetworkHandler.class.getName()).log(Level.SEVERE, null, ex);
                statusMessageLabel.setText(ex.getMessage());
            }
        }
    }

    public void setupComponents() {
        computeButton.addMouseListener(new MouseAdapter() {

            public void mouseReleased(MouseEvent e) {
                new Thread(new Runnable() {

                    synchronized public void run() {
                        try {
                            mxGraphComponent gc = (mxGraphComponent) tabs.getSelectedComponent();
                            gc.setEnabled(false);
                            BayesianNetwork network = networks.get(gc.getGraph());
                            progressBar.setVisible(true);
                            progressBar.setIndeterminate(true);
                            mxGraph graph = gc.getGraph();
                            if (network.knownVariables.size() > 0 && !network.soughtVariableLabel.isEmpty()) {
                                network.computeVarDistrByKnownVariables(network.knownVariables, network.soughtVariableLabel);
                            } else {
                                statusMessageLabel.setText("Nie zaznaczono zmiennych");
                            }
                            graph.refresh();
                            this.wait(0);
                            progressBar.setIndeterminate(false);
                            progressBar.setVisible(false);
                            gc.setEnabled(true);


                        } catch (InterruptedException ex) {
                            Logger.getLogger(ViewNetworkHandler.class.getName()).log(Level.SEVERE, null, ex);
                            statusMessageLabel.setText("Błąd w obliczeniach");

                        }
                        return;
                    }
                }).start();

            }
        });
        openButton.addMouseListener(new java.awt.event.MouseAdapter() {

            public void mouseClicked(java.awt.event.MouseEvent evt) {
                openButtonMouseClicked(evt);
            }
        });

    }

    public void addNetwork(BayesianNetwork network) {
        mxGraph graph = super.addGraph();
        mxGraphComponent graphComponent = (mxGraphComponent) tabs.getSelectedComponent();
        setGraphListener2(graphComponent);
        networks.put(graph, network);
        int x = 10, y = 10;
//        Collection<NetworkVertex> vertices = network.getVertexes();
        Object parent = graph.getDefaultParent();
        Iterator i = network.getVertexes().entrySet().iterator();
        addVertices(graph, i, parent, x, y, network);
        addEdges(network, graph, i, parent);
    }

    public void setGraphListener2(final mxGraphComponent graphComponent) {

        graphComponent.getGraphControl().addMouseListener(new MouseAdapter() {

            public void mouseReleased(MouseEvent e) {
                BayesianNetwork net = networks.get(((mxGraphComponent) tabs.getSelectedComponent()).getGraph());
                mxCell cell = (mxCell) graphComponent.getCellAt(e.getX(), e.getY());
                if (cell != null) {
                    String label = (String) cell.getValue();
                    HashMap<String, NetworkVertex> map = new HashMap<String, NetworkVertex>(net.getVertexes());
                    NetworkVertex current = map.get(label);
                    if (addEdgeToggleButton.isSelected() && cell.isVertex()) {
//                        addEdge(cell);
                    } else if (selectKnownButton.isSelected()) {
                        processSelectKnown(cell, net, current);
                    } else if (selectSoughtButton.isSelected()) {
                        processSelectSought(cell, net, current);
                    } else {
//                        editProperty(cell);
                    }
                } else if (addVertexToggleButton.isSelected()) {
//                    addVertex(e.getX(), e.getY());
                }
            }

            private void processSelectSought(mxCell cell, BayesianNetwork net, NetworkVertex current) {
                if (cell.isVertex()) {
                    if (net.soughtVariableLabel.equals(current.getName())) {
                        net.soughtVariableLabel = new String();
                        statusMessageLabel.setText("Usunieto szukana zmienna");
                    } else {
                        net.soughtVariableLabel = current.getName();
                        statusMessageLabel.setText("Dodano szukana zmienna");
                    }
                }
            }

            private void processSelectKnown(mxCell cell, BayesianNetwork net, NetworkVertex current) {
                if (cell.isVertex()) {
                    if (net.knownVariables.containsKey(current.getName())) {
                        net.knownVariables.remove(current.getName());
                        statusMessageLabel.setText("Usunieto dana zmienna");
                    } else {
                        net.knownVariables.put(current.getName(), current.getAllowedValue(1)); //?????????????????
                        statusMessageLabel.setText("Dodano dana zmienna");
                    }
                }
            }
        });
        /*
        graphComponent.getGraphControl().addKeyListener(new KeyListener() {

        public void keyTyped(KeyEvent e) {
        if (e.equals(KeyEvent.VK_DELETE)) {
        activeGraph.removeSelectionCell(activeGraph.getSelectionCell());
        }
        System.out.print("delete\n");
        }

        public void keyPressed(KeyEvent e) {
        if (e.equals(KeyEvent.VK_DELETE)) {
        activeGraph.removeSelectionCell(activeGraph.getSelectionCell());
        }
        System.out.print("delete\n");
        }

        public void keyReleased(KeyEvent e) {
        if (e.equals(KeyEvent.VK_DELETE)) {
        activeGraph.removeSelectionCell(activeGraph.getSelectionCell());
        }
        System.out.print("delete\n");
        }
        });*/
    }

    public BayesianNetwork getBayes() {


        BayesianNetwork bayesianNetwork = new BayesianNetwork();
        NetworkVertex vertex1 = new NetworkVertex(0, "vertex1");
        NetworkVertex vertex2 = new NetworkVertex(1, "vertex2");
        NetworkVertex vertex3 = new NetworkVertex(2, "vertex3");
        NetworkVertex vertex4 = new NetworkVertex(3, "vertex4");
        NetworkVertex vertex5 = new NetworkVertex(4, "vertex5");

        vertex1.addAllowedValue(new RandomVariableValue<String>(vertex1, "vertex1Val1"));
        vertex1.addAllowedValue(new RandomVariableValue<String>(vertex1, "vertex1Val2"));

        vertex2.addAllowedValue(new RandomVariableValue<String>(vertex2, "vertex2Val1"));
        vertex2.addAllowedValue(new RandomVariableValue<String>(vertex2, "vertex2Val2"));
        vertex2.addAllowedValue(new RandomVariableValue<String>(vertex2, "vertex2Val3"));

        vertex3.addAllowedValue(new RandomVariableValue<String>(vertex3, "vertex3Val1"));
        vertex3.addAllowedValue(new RandomVariableValue<String>(vertex3, "vertex3Val2"));

        vertex4.addAllowedValue(new RandomVariableValue<String>(vertex4, "vertex4Val1"));
        vertex4.addAllowedValue(new RandomVariableValue<String>(vertex4, "vertex4Val2"));

        vertex5.addAllowedValue(new RandomVariableValue<String>(vertex5, "vertex5Val1"));
        vertex5.addAllowedValue(new RandomVariableValue<String>(vertex5, "vertex5Val2"));
        vertex5.addAllowedValue(new RandomVariableValue<String>(vertex5, "vertex5Val3"));
        vertex5.addAllowedValue(new RandomVariableValue<String>(vertex5, "vertex5Val4"));

        vertex2.addParent(vertex1);
        vertex3.addParent(vertex2);
        vertex4.addParent(vertex2);
        vertex5.addParent(vertex3);

        Vector<RandomVariableValue<String>> emptyDependantList = new Vector<RandomVariableValue<String>>();

        vertex1.setCondDistrRow(vertex1.getAllowedValue(0), 0.1f, emptyDependantList);
        vertex1.setCondDistrRow(vertex1.getAllowedValue(1), 0.9f, emptyDependantList);

        vertex2.setCondDistrRow(vertex2.getAllowedValue(0), 0.1f, vertex1.getAllowedValue(0));
        vertex2.setCondDistrRow(vertex2.getAllowedValue(0), 0.7f, vertex1.getAllowedValue(1));
        vertex2.setCondDistrRow(vertex2.getAllowedValue(1), 0.2f, vertex1.getAllowedValue(0));
        vertex2.setCondDistrRow(vertex2.getAllowedValue(1), 0.05f, vertex1.getAllowedValue(1));
        vertex2.setCondDistrRow(vertex2.getAllowedValue(2), 0.7f, vertex1.getAllowedValue(0));
        vertex2.setCondDistrRow(vertex2.getAllowedValue(2), 0.25f, vertex1.getAllowedValue(1));

        vertex3.setCondDistrRow(vertex3.getAllowedValue(0), 0.1f, vertex2.getAllowedValue(0));
        vertex3.setCondDistrRow(vertex3.getAllowedValue(0), 0.15f, vertex2.getAllowedValue(1));
        vertex3.setCondDistrRow(vertex3.getAllowedValue(0), 0.25f, vertex2.getAllowedValue(2));
        vertex3.setCondDistrRow(vertex3.getAllowedValue(1), 0.9f, vertex2.getAllowedValue(0));
        vertex3.setCondDistrRow(vertex3.getAllowedValue(1), 0.85f, vertex2.getAllowedValue(1));
        vertex3.setCondDistrRow(vertex3.getAllowedValue(1), 0.75f, vertex2.getAllowedValue(2));

        vertex4.setCondDistrRow(vertex4.getAllowedValue(0), 0.01f, vertex2.getAllowedValue(0));
        vertex4.setCondDistrRow(vertex4.getAllowedValue(0), 0.015f, vertex2.getAllowedValue(1));
        vertex4.setCondDistrRow(vertex4.getAllowedValue(0), 0.025f, vertex2.getAllowedValue(2));
        vertex4.setCondDistrRow(vertex4.getAllowedValue(1), 0.99f, vertex2.getAllowedValue(0));
        vertex4.setCondDistrRow(vertex4.getAllowedValue(1), 0.985f, vertex2.getAllowedValue(1));
        vertex4.setCondDistrRow(vertex4.getAllowedValue(1), 0.975f, vertex2.getAllowedValue(2));

        vertex5.setCondDistrRow(vertex5.getAllowedValue(0), 0.3f, vertex3.getAllowedValue(0));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(0), 0.2f, vertex3.getAllowedValue(1));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(1), 0.1f, vertex3.getAllowedValue(0));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(1), 0.1f, vertex3.getAllowedValue(1));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(2), 0.3f, vertex3.getAllowedValue(0));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(2), 0.5f, vertex3.getAllowedValue(1));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(3), 0.3f, vertex3.getAllowedValue(0));
        vertex5.setCondDistrRow(vertex5.getAllowedValue(3), 0.2f, vertex3.getAllowedValue(1));

        bayesianNetwork.addVertex(vertex1);
        bayesianNetwork.addVertex(vertex2);
        bayesianNetwork.addVertex(vertex3);
        bayesianNetwork.addVertex(vertex4);
        bayesianNetwork.addVertex(vertex5);

        return bayesianNetwork;
    }
}
